package com.lianyou.chapter03.crossparameter;

import jakarta.validation.*;
import jakarta.validation.constraintvalidation.SupportedValidationTarget;
import jakarta.validation.constraintvalidation.ValidationTarget;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.List;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({ METHOD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { LuggageCountMatchesPassengerCount.Validator.class })
@Documented
public @interface LuggageCountMatchesPassengerCount {

	String message() default "{com.lianyou.chapter03.crossparameter.LuggageCountMatchesPassengerCount.message}";

	Class<?>[] groups() default { };

	Class<? extends Payload>[] payload() default { };

	// 在具有参数和返回值的方法上声明这样的约束时，无法确定预期的约束目标。因此，
	// 同时具有通用和交叉参数的约束必须定义一个成员validationAppliesTo()，该成员允许约束用户指定约束的目标
	// IMPLICIT 含蓄的, 返回值有验证返回值, 参数又验证参数, 都有就都验真
	// RETURN_VALUE 返回值验证
	// PARAMETERS 参数验证
	ConstraintTarget validationAppliesTo() default ConstraintTarget.IMPLICIT;

	int piecesOfLuggagePerPassenger() default 1;



	@SupportedValidationTarget({
			ValidationTarget.PARAMETERS, // 用来验证方法和构造方法上的多个参数交叉验证
			ValidationTarget.ANNOTATED_ELEMENT  //  加这个注解, 说明他也可以是一个普通注解, 就是单个参数验证的
	})
	class Validator
			implements ConstraintValidator<LuggageCountMatchesPassengerCount, Object[]> {

		int piecesOfLuggagePerPassenger;

		@Override
		public void initialize(LuggageCountMatchesPassengerCount constraintAnnotation) {
			piecesOfLuggagePerPassenger = constraintAnnotation.piecesOfLuggagePerPassenger();
		}

		@Override
		public boolean isValid(Object[] value, ConstraintValidatorContext context) {
			if ( value.length != 2 ) {
				throw new IllegalArgumentException( "Illegal method signature" );
			}

			//leave null-checking to @NotNull on individual parameters
			if ( value[0] == null || value[1] == null ) {
				return true;
			}

			if ( !( value[0] instanceof List) || !( value[1] instanceof List ) ) {
				throw new IllegalArgumentException(
						"Illegal method signature, expected two " +
								"parameters of type Date."
				);
			}

			return ((List)value[0]).size() == piecesOfLuggagePerPassenger && ((List)value[1]).size() == piecesOfLuggagePerPassenger;
		}
	}
}
